package com.rizzo.analytics.services.web.controller.v1;

import com.mangofactory.swagger.annotations.ApiErrors;
import com.mangofactory.swagger.annotations.ApiModel;
import com.rizzo.analytics.domain.account.Account;
import com.rizzo.analytics.domain.info.Info;
import com.rizzo.analytics.services.web.controller.v1.error.InfoNotFoundException;
import com.rizzo.analytics.services.web.controller.v1.error.ValidationException;
import com.rizzo.infrastructure.dark.DarkLaunch;
import com.rizzo.infrastructure.domain.KeyType;
import com.rizzo.infrastructure.performance.Monitor;
import com.rizzo.infrastructure.quota.Quota;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiError;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller("infoController")
@RequestMapping(value = "/info", produces = "application/json")
@Api(value = "/info",
        description = "This is the one stop shop for discovering all the data (categories or service-methods) for a user and his applications. " +
                "The results of this endpoint can be used to retrieve more specific data from the other endpoints. " +
                "This provides for a mechanism of guided search in stead of bulk querying the endpoints.")
public class InfoController extends RizzoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(InfoController.class);

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @Quota(maxCalls = 30, expireSeconds = 60)
    @DarkLaunch(name = "get-info")
    @RequestMapping(value = "/{application}", method = RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "Lists all possible informational keys",
            notes = "This endpoint returns all the available data about an application. " +
                    "This endpoint can only be called when logged in!",
            responseClass = "com.rizzo.analytics.domain.info.Info", tags = "info")
    @ApiErrors({InfoNotFoundException.class, ValidationException.class})
    @com.wordnik.swagger.annotations.ApiErrors(
            {@ApiError(code = 404, reason = "Quota exceeded"),
                    @ApiError(code = 404, reason = "Not available")}
    )
    @ApiModel(type = Info.class)
    public Info getInfo(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application " +
                            "(see output of '/application' for possible values)") String application) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        LOGGER.debug("Asking for all the keys of [application : '{}'] and [user : '{}']", application, user);
        return analyticsDelegator.getInfo(user, application, KeyType.ALL, WILDCARD, WILDCARD, WILDCARD);
    }

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @Quota(maxCalls = 30, expireSeconds = 120)
    @DarkLaunch(name = "get-info-with-criteria")
    @RequestMapping(value = "/{application}/{category}", method = RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "Lists all possible informational keys",
            notes = "This endpoint returns the available info about an application. " +
                    "Results from this endpoint are filterable by category, keyType, instanceName and instanceIndex. " +
                    "This endpoint can only be called when logged in! " +
                    "Be aware that the params instanceName and instanceIndex are only relevant when querying " +
                    "for PERFORMANCE keyTypes!",
            responseClass = "com.rizzo.analytics.domain.info.Info", tags = "info")
    @ApiErrors({InfoNotFoundException.class, ValidationException.class})
    @com.wordnik.swagger.annotations.ApiErrors(
            {@ApiError(code = 404, reason = "Quota exceeded"),
                    @ApiError(code = 404, reason = "Not available")}
    )
    @ApiModel(type = Info.class)
    public Info getInfoWithCriteria(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application " +
                            "(see output of '/application' for possible values)") String application,
            @PathVariable("category")
            @ApiParam(name = "category", required = true,
                    value = "The category or method of the service (wildcards '*' are allowed but case-sensitive)") String category,
            @RequestParam(value = "keyType", defaultValue = "ALL", required = false)
            @ApiParam(name = "keyType", defaultValue = "ALL", allowableValues = KeyType.allowableValues, required = false,
                    value = "The type of the keys to return") KeyType keyType,
            @RequestParam(value = "instanceName", defaultValue = WILDCARD, required = false)
            @ApiParam(name = "instanceName", defaultValue = WILDCARD, required = false,
                    value = "The instanceName from which the data originated (wildcards '*' are allowed)") String instanceName,
            @RequestParam(value = "instanceIndex", defaultValue = WILDCARD, required = false)
            @ApiParam(name = "instanceIndex", defaultValue = WILDCARD, required = false,
                    value = "The instanceIndex from which the data originated (wildcards '*' are allowed)") String instanceIndex) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        LOGGER.debug("Asking for all the keys of [application : '{}'] and [user : '{}'] with [category: '{}']", application, user, category);
        return analyticsDelegator.getInfo(user, application, keyType, category, instanceName, instanceIndex);
    }

}
